<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2017/9/1
 * Time: 9:58
 */

/**
 * Class classDemo
 * @User: yfl
 * @Time:2017年9月1日 10:01:12
 * @description:  PHP多线程编程之管道通信实例分析
 * 本文实例讲述了PHP多线程编程之管道通信用法。分享给大家供大家参考。具体分析如下：
 * 一个线程如果是个人英雄主义，那么多线程就是集体主义，你不再是一个独行侠，而是一个指挥家。
 * 管道通信：
 * 1. 管道可以认为是一个队列，不同的线程都可以往里面写东西，也都可以从里面读东西。写就是
 * 在队列末尾添加，读就是在队头删除。
 * 2. 管道一般有大小，默认一般是4K，也就是内容超过4K了，你就只能读，不能往里面写了。
 * 3. 默认情况下，管道写入以后，就会被阻止，直到读取他的程序读取把数据读完。而读取线程也会被阻止，
 * 直到有进程向管道写入数据。当然，你可以改变这样的默认属性，用stream_set_block  函数，设置成非阻断模式。
 * 下面是我分装的一个管道的类（这个类命名有问题，没有统一，没有时间改成统一的了，我一般先写测试代码，最后分装，所以命名上可能不统一）：
 * thread 线程  pipe 管道 posix  可移植性操作系统接口
 * @from http://www.jb51.net/article/61856.htm
 */
class classDemo
{
    public $fifoPath;
    private $w_pipe;
    private $r_pipe;

    /**
     * classDemo constructor.
     * @param string $name 管道的名称
     * @param int $mode 管道的权限  默认情况下所有用户都可以读写
     * @description:自动创建管道
     */
    public function __construct($name = 'pipeName', $mode = 0666)
    {
//        $fifoPath=posix_getppid();   //posix_getpid 取得当前服务器进程号 此函数只有在Linux下有效 在windows下可以使用get_current_user()。
        if (function_exists('posix_getppid')) {
            $fifoPath = posix_getppid();
        } else {
//            $fifoPath=get_current_user();  //获取当前 PHP 脚本所有者名称
            $fifoPath = "/tmp/$name." . getmypid();//— 获取 PHP 进程的 ID
//            echo $fifoPath;
            if (!file_exists($fifoPath)) {
                if (!posix_mkfifo($fifoPath, $mode)) {   //posix_mkfifo  创建一个fifo特殊文件(一个命名管道)   (fifo 先进先出  first in，first out)
                    echo "创建{$fifoPath}文件失败";
                    return false;
                }
            } else {
                echo "{$fifoPath}已经存在";
                return false;
            }
            $this->fifoPath = $fifoPath;
        }
    }

    /**
     * @return bool
     * @User: yfl
     * @Time:二〇一七年九月一日 11:06:38
     * @description:写管道开始 打开文件
     */
    public function open_write()
    {
        $this->w_pipe = fopen($this->fifoPath, 'w');
        if ($this->w_pipe == null) {
            echo "open pipe{$this->fifoPath} for write fail";
            return false;
        }
        return true;
    }

    /**
     * @param $data
     * @return bool|int
     * @User: yfl
     * @Time: 二〇一七年九月一日 11:09:11
     * @description: 写入数据
     */
    public function write($data)
    {
        return fwrite($this->w_pipe, $data);
    }
    //写入全部数据
    public function write_all($data)
    {
        $w_pipe = fopen($this->fifoPath, 'w');
        fwrite($w_pipe, $data);
        fclose($w_pipe);
    }

    /**
     * @return bool
     * @User: yfl
     * @Time: 二〇一七年九月一日 11:13:22
     * @description: 关闭资源
     */
    public function close_write()
    {
        return fclose($this->w_pipe);
    }


    //读管道开始
    public function open_read()
    {
        $this->r_pipe = fopen($this->fifoPath, 'r');
        if ($this->r_pipe == null) {
            error("open pipe {$this->fifoPath} for read error.");       return false;
        }
        return true;
    }

    /**
     * @param int $byte
     * @return bool|string
     * @User: yfl
     * @Time:二〇一七年九月一日 11:18:05
     * @description: 读取管道数据 一次读取1024字节
     */
    public function read($byte=1024)
    {
      return fread($this->r_pipe,$byte);
    }

    /**
     * @return string
     * @User: yfl
     * @Time:2017年9月1日 11:21:40
     * @description:读取管道文件的所有数据
     */
    public function read_all()
    {
        $r_pipe=fopen($this->fifoPath,'r');
        $data='';
        while(!feof($r_pipe)){
          $data.=fread($r_pipe,1024);
        }
        fclose($r_pipe);
        return $data;
    }

    /**
     * @return bool
     * @User: yfl
     * @Time:
     * @description:关闭资源
     */
    public function close_read()
    {
        return fclose($this->r_pipe);
    }

    /**
     * @return bool
     * @User: yfl
     * @Time: 2017年9月1日 11:24:03
     * @description: 删除管道
     */
    public function rm_pipe()
    {
        return unlink($this->fifoPath);
    }
}

$obj = new classDemo();